package com.honglang.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;


public class GenericDaoImpl <T,ID extends Serializable> extends HibernateDaoSupport implements GenericDao <T,ID>{

	private Class<T> persistentClass;
	
	@SuppressWarnings("unchecked")
	public GenericDaoImpl(){
		 this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}
	/**
	 * Get entity by Id
	 * @param id
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public T getById(ID id){
		return (T) this.getHibernateTemplate().get(persistentClass,id);	
	}
	
	/**
	 * get All Entities 
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> getAll(){
		
		return this.getHibernateTemplate().loadAll(persistentClass);
	}
	
	/**
	 * find entities by detachedCriteria  
	 * @param criteria
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> getByDetachedCriteria(DetachedCriteria criteria){
		return this.getHibernateTemplate().findByCriteria(criteria);
	}
	
	
	
	/**
	 * get the rowCount in a criteria list;
	 * @param criteria
	 * @return
	 */
	public Integer getRowCountByDetachedCriteria(DetachedCriteria criteria){
		criteria.setProjection(Projections.rowCount());
		return  (Integer)this.getHibernateTemplate().findByCriteria(criteria).get(0);
		
	}
	
	
	/**
	 * find entities by detachedCriteria  
	 * @param criteria
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> getByDetachedCriteriaInMaxResult(DetachedCriteria criteria,int maxResult){
		Session session= getHibernateTemplate().getSessionFactory().openSession();
		Transaction txn = session.beginTransaction();
		List results = criteria.getExecutableCriteria(session).setMaxResults(maxResult).list();
		txn.commit();
		session.close();
		return results;
	}
	
	
	/**
	 * get entities by criteria in pager;
	 * @param criteria
	 * @param maxResult
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> getByDetachedCriteriaInPager(DetachedCriteria criteria,int startIndex,int maxResult){
		Session session= getHibernateTemplate().getSessionFactory().openSession();
		Transaction txn = session.beginTransaction();
		List results = criteria.getExecutableCriteria(session).setFirstResult(startIndex).setMaxResults(maxResult).list();
		txn.commit();
		session.close();
		return results;
	}
	
	
	/**
	 * find entities by detachedCriteria;
	 * @param example
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> getByExample(Object exampleObject){
		
		return this.getHibernateTemplate().findByExample(exampleObject);
	}
	
	
	
	
	
	
	/**
	 * saveOrUpdate a entity And return it
	 * @param entity
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public T merge(T entity){
		
		return (T) this.getHibernateTemplate().merge(entity);
	}
	
	
	/**
	 * saveOrUpdate a entity
	 * @param entity
	 */
	public void saveOrUpdate(T entity){
		this.getHibernateTemplate().saveOrUpdate(entity);
 	} 
	
	/**
	 * Batch Save or Update entities
	 * @param coll
	 */
	public void batchSaveOrUpdate(Collection<T> coll){
		this.getHibernateTemplate().saveOrUpdateAll(coll);
	}
	
	/**
	 * delete Entity;
	 * @param entity
	 */
	public void delete(T entity){
		this.getHibernateTemplate().delete(entity);
		
	}
	
	
	/**
	 * delete Entity by entity id;
	 * @param id
	 */
	public void delete(final Integer id){
		this.getHibernateTemplate().execute(new HibernateCallback(){

			@Override
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				
				session.getTransaction().begin();
				session.createQuery("delete " + getPersistentClass().getName() + " where id = ? ")
				       .setParameter(0,id)
				       .executeUpdate();
				session.getTransaction().commit();
				return null;
			}});
	}
	
	
	/**
	 * delete All the entites;
	 * @param coll
	 */
	public void deleteAll(Collection<T> coll){
		this.getHibernateTemplate().deleteAll(coll);
	}
	
	
	public Class<T> getPersistentClass() {
		return persistentClass;
	}
	
	
	/**
	 * get the RowCount of entites;
	 * @return
	 */
	public Integer getRowCountOfAllEntites(){
		DetachedCriteria criteria = DetachedCriteria.forClass(this.persistentClass) ;
		criteria.setProjection(Projections.rowCount());
		return (Integer)this.getHibernateTemplate().findByCriteria(criteria).get(0);
	}
	
	
	public static void main(String[] args){
		System.out.println(new GenericDaoImpl<String,Integer>().getPersistentClass());
	}
	
	
	/**
	 * get the  entities  of one page
	 * @param pageSize
	 * @param pageNo
	 * @return
	 */
	public List<?> getEntitiesPerPage(int pageSize,int pageNo){
		Session session= getHibernateTemplate().getSessionFactory().openSession();
		Criteria criteria=session.createCriteria(this.getPersistentClass());
		int startIndex=pageSize*(pageNo-1);
		criteria.addOrder(Order.desc("id"));
		criteria.setFirstResult(startIndex);
		criteria.setMaxResults(pageSize);
		List<?> result=criteria.list();
		session.close();
		return result;
	}
	
	/**
	 * get the  entities by Example Query;
	 * @param pageSize
	 * @param pageNo
	 * @return
	 */
	public List<?> findByExampleQuery(Example example){
		Session session= getHibernateTemplate().getSessionFactory().openSession();
		Criteria criteria=session.createCriteria(this.getPersistentClass());
		List<?> result=criteria.add(example).list();
		session.close();
		return result;
	}
	
}
